// https://zhuanlan.zhihu.com/p/379827158
import path from 'node:path';
import {
  Appender,
  Configuration,
  Levels,
  ConsoleAppender,
  Layout,
  DateFileAppender,
  LogLevelFilterAppender,
} from 'log4js';

const baseLogPath = path.resolve(__dirname, '../../log');

/** console appender */
export class AppenderOfConsole implements ConsoleAppender {
  type: 'console';
  layout?: Layout;
}
/** datefile appender */
export class AppenderOfDateFile implements DateFileAppender {
  type: 'dateFile'; //会写入文件并按照日期分类
  filename: string; //日志文件名，会命名为：access.当前时间.log
  pattern?: string; //时间格式
  layout?: Layout;
  encoding?: string;
  mode?: number;
  flags?: string;
  compress?: boolean;
  keepFileExt?: boolean; //是否保留文件后缀
  fileNameSep?: string;
  alwaysIncludePattern?: boolean;
  numBackups?: number;
  constructor(dateFileOptions: Omit<DateFileAppender, 'type'>) {
    this.type = 'dateFile';
    this.filename = dateFileOptions.filename;
    this.pattern = dateFileOptions.pattern;
    this.layout = dateFileOptions.layout;
    this.encoding = dateFileOptions.encoding;
    this.mode = dateFileOptions.mode;
    this.flags = dateFileOptions.flags;
    this.compress = dateFileOptions.compress;
    this.keepFileExt = dateFileOptions.keepFileExt;
    this.fileNameSep = dateFileOptions.fileNameSep;
    this.alwaysIncludePattern = dateFileOptions.alwaysIncludePattern;
    this.numBackups = dateFileOptions.numBackups;
  }
}

/** logLevelFilter appender */
export class AppenderOfLogLevelFilter implements LogLevelFilterAppender {
  type: 'logLevelFilter';
  appender: string;
  level: string;
  maxLevel?: string;
  constructor(logLevelFilterOptions: Omit<LogLevelFilterAppender, 'type'>) {
    this.type = 'logLevelFilter';
    this.appender = logLevelFilterOptions.appender;
    this.level = logLevelFilterOptions.level;
    this.maxLevel = logLevelFilterOptions.maxLevel;
  }
}

/** log4js 自定义配置 */
export class Log4jsConfig implements Configuration {
  appenders: { [name: string]: Appender };
  categories: { [name: string]: { appenders: string[]; level: string; enableCallStack?: boolean } };
  //   pm2?: boolean; //使用pm2的时候开放
  //   pm2InstanceVar?: string;
  //   levels?: Levels | { [name: string]: { value: number; colour: string } };
  //   disableClustering?: boolean;
  constructor() {
    this.genAllAppender();
    this.genCategories();
  }

  public genAllAppender() {
    this.genConsoleAppender();
    this.genDateFileAppenderOfAccess();
    this.genDateFileAppenderOfApp();
    this.genDateFileAppenderOfErrorFile();
    this.genDateFileAppenderOfErrors();
  }

  // console
  public genConsoleAppender() {
    this.appenders['console'] = new AppenderOfConsole();
  }

  // access
  public genDateFileAppenderOfAccess() {
    this.appenders['access'] = new AppenderOfDateFile({
      filename: `${baseLogPath}/access/access.log`,
      alwaysIncludePattern: true,
      pattern: 'yyyyMMdd',
      numBackups: 3,
      keepFileExt: true,
    });
  }

  // app
  public genDateFileAppenderOfApp() {
    this.appenders['app'] = new AppenderOfDateFile({
      filename: `${baseLogPath}/app-out/app.log`,
      alwaysIncludePattern: true,
      layout: {
        type: 'pattern',
        pattern: '{"date":"%d","level":"%p","category":"%c","host":"%h","pid":"%z","data":\'%m\'}',
      },
      pattern: 'yyyyMMdd',
      numBackups: 3,
      keepFileExt: true,
    });
  }

  // errorFile
  public genDateFileAppenderOfErrorFile() {
    this.appenders['errorFile'] = new AppenderOfDateFile({
      filename: `${baseLogPath}/errors/error.log`,
      alwaysIncludePattern: true,
      layout: {
        type: 'pattern',
        pattern: '{"date":"%d","level":"%p","category":"%c","host":"%h","pid":"%z","data":\'%m\'}',
      },
      pattern: 'yyyyMMdd',
      numBackups: 3,
      keepFileExt: true,
    });
  }

  // errors
  public genDateFileAppenderOfErrors() {
    this.appenders['errors'] = new AppenderOfLogLevelFilter({
      level: 'ERROR',
      appender: 'errorFile',
    });
  }

  public genCategories() {
    this.categories['default'] = { appenders: ['console', 'app', 'errors'], level: 'DEBUG' };
    this.categories['info'] = { appenders: ['console', 'app', 'errors'], level: 'info' };
    this.categories['access'] = { appenders: ['console', 'app', 'errors'], level: 'info' };
    this.categories['http'] = { appenders: ['access'], level: 'DEBUG' };
  }
}
